﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace CPPEI.ETL.DataServiceInterface
{
    public enum DataType
    {
        Value,
        DataTable,
        XmlNode,
        Object,
        Array
    }

    public interface IData
    {
        DataType Type { get; }

        object Data { get; }

        List<Column> GetSchema();

        int RowCount { get; }

        Row Get(int index);
    }

    public class Row
    {
        private Hashtable _items = new Hashtable();

        public int RowIndex { get; set; }

        public Row(int rowIndex)
        {
            RowIndex = rowIndex;
        }

        internal void Add(string key, string value)
        {
            _items.Add(key, value);
        }

        public static void Add(Row row, string key, string value)
        {
            row.Add(key, value);
        }

        public void Set(string key, object value)
        {
            try
            {
                _items[key] = value;
            }
            catch(Exception ex)
            {

            }
        }

        public static void Set(Row row, string key, string value)
        {
            row.Set(key, value);
        }

        public string Get(string key)
        {
            try
            {
                object value = _items[key];
                if (value != null)
                {
                    return value.ToString();
                }
                return string.Empty;
            }
            catch(Exception ex)
            {
                return null;
            }
        }
    }

    public class Column
    {
        /// <summary>
        /// 列名称，这个只取最后一个名字
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 列的路径，基于数据结果的完整路径
        /// </summary>
        public string Path { get; private set; }

        public string TypeFullName { get; set; }

        public Type Type { get; set; }

        [Obsolete("使用3个参数的重载")]
        public Column(string name, Type type)
        {
            Name = name;
            Type = type;
            TypeFullName = Type.FullName;
            this.Path = name;
        }
        public Column(string name, string path, Type type)
        {
            this.Path = path;
            Name = name;
            Type = type;
            TypeFullName = Type.FullName;
        }
    }

    public class ValueData : IData
    {
        /// <summary>
        /// 从数据类型里获取列的信息
        /// </summary>
        /// <param name="dataType"></param>
        /// <returns></returns>
        public static List<Column> GetColumns(Type dataType)
        {
            List<Column> columns = new List<Column>();
            columns.Add(new Column("RESULT", "RESULT", dataType));
            return columns;
        }

        public DataType Type
        {
            get;
            private set;
        }

        public object Data
        {
            get;
            private set;
        }

        public ValueData(object data)
        {
            Type = DataType.Value;
            Data = data;
        }

        public override string ToString()
        {
            return Data.ToString();
        }

        private List<Column> _columns;
        public List<Column> GetSchema()
        {
            if(_columns == null)
            {
                _columns = GetColumns(Data.GetType());
            }
            return _columns;
        }

        public int RowCount
        {
            get { return 1; }
        }

        public Row Get(int index)
        {
            Row row = new Row(index);
            row.Add("RESULT", Convert.ToString(Data));
            return row;
        }
    }

    public class DataTableData : IData
    {
        public DataType Type
        {
            get;
            private set;
        }

        public object Data
        {
            get;
            private set;
        }

        private DataTable _dataTable;

        private List<Column> _columns = null;

        public DataTableData(DataTable data)
        {
            Type = DataType.DataTable;
            Data = data;
            _dataTable = data;
        }

        public List<Column> GetSchema()
        {
            if(_columns == null)
            {
                _columns = new List<Column>();
                DataTable dataTable = Data as DataTable;
                if (dataTable != null)
                {
                    foreach (DataColumn dtColumn in dataTable.Columns)
                    {
                        _columns.Add(new Column(dtColumn.ColumnName, dtColumn.ColumnName, dtColumn.DataType));// typeof(string).FullName));
                    }
                }
            }
            return _columns;
        }
        public int RowCount
        {
            get { return _dataTable.Rows.Count; }
        }

        public Row Get(int index)
        {
            List<Column> columns = GetSchema();

            DataRow dtRow = _dataTable.Rows[index];

            Row row = new Row(index);
            for (int colIndex = 0; colIndex < columns.Count; colIndex++)
            {
                row.Add(columns[colIndex].Name, Convert.ToString(dtRow[columns[colIndex].Name]));
            }

            return row;
        }
    }

    public class ObjectData : IData
    {
        /// <summary>
        /// 从数据类型里获取列的信息
        /// </summary>
        /// <param name="dataType"></param>
        /// <returns></returns>
        public static List<Column> GetColumns(Type dataType)
        {
            List<Column> columns = new List<Column>();
            List<string> propertyPaths = null;
            List<Type> propertyTypes = null;
            CPPEI.ETL.Infrastructure.PropertyUtil.GetPropertyPathList(dataType, "RET", out propertyPaths, out propertyTypes);

            for (int index = 0; index < propertyPaths.Count; index++)
            {
                Column column = new Column(propertyPaths[index].Split(new char[] { '.' }).Last(), propertyPaths[index], propertyTypes[index]);

                columns.Add(column);
            }
            return columns;
        }

        public DataType Type
        {
            get;
            private set;
        }

        public object Data
        {
            get;
            private set;
        }

        private object _object;

        private List<Column> _columns = null;

        public ObjectData(object data)
        {
            Type = DataType.Object;
            Data = data;
            _object = data;
        }

        public List<Column> GetSchema()
        {
            if (_columns == null)
            {
                _columns = GetColumns(Data.GetType());
            }
            return _columns;
        }
        public int RowCount
        {
            get { return 1; }
        }

        public Row Get(int index)
        {
            List<Column> columns = GetSchema();

            if (index > 0)
            {
                return null;
            }
            Row row = new Row(index);
            List<string> paths = null;
            List<object> values = null;
            CPPEI.ETL.Infrastructure.PropertyUtil.GetPropertyPathValueList(_object.GetType(), _object, "RET", out paths, out values);

            for (int colIndex = 0; colIndex < columns.Count; colIndex++)
            {
                if (values[index] != null)
                {
                    Row.Add(row, columns[colIndex].Name, values[colIndex].ToString());
                }
                else
                {
                    Row.Add(row, columns[colIndex].Name, null);
                }
            }

            return row;
        }
    }

    public class ComplexData : IData
    {
        public List<IData> _innerDataList;

        public DataType Type
        {
            get;
            private set;
        }

        public object Data
        {
            get
            {
                return _innerDataList.FirstOrDefault();
            }
        }

        private List<Column> _columns = null;

        public ComplexData(List<IData> dataList)
        {
            _innerDataList = dataList;
            Type = dataList.First().Type;
            for (int index = 0; index < dataList.Count; index++)
            {
                _rowCount += dataList[index].RowCount;
            }
        }

        /// <summary>
        /// 从数据类型里获取列的信息
        /// </summary>
        /// <param name="dataType"></param>
        /// <returns></returns>
        public static List<Column> GetColumns(Type dataType)
        {
            List<Column> columns = new List<Column>();
            List<string> propertyPaths = null;
            List<Type> propertyTypes = null;
            CPPEI.ETL.Infrastructure.PropertyUtil.GetPropertyPathList(dataType, "RET", out propertyPaths, out propertyTypes);

            for (int index = 0; index < propertyPaths.Count; index++)
            {
                Column column = new Column(propertyPaths[index].Split(new char[] { '.' }).Last(), propertyPaths[index], propertyTypes[index]);

                columns.Add(column);
            }
            return columns;
        }

        public List<Column> GetSchema()
        {
            if (_columns == null)
            {
                _columns = GetColumns(Data.GetType());
            }
            return _columns;
        }
        
        private int _rowCount = 0;

        public int RowCount
        {
            get { return _rowCount; }
        }

        public Row Get(int index)
        {
            int start = 0;
            int end = 0;
            for (int dataIndex = 0; dataIndex < _innerDataList.Count; dataIndex++)
            {
                int rowCount = _innerDataList[dataIndex].RowCount;

                end += rowCount;

                if(index >= start && index < end)
                {
                    return _innerDataList[dataIndex].Get(index - start);
                }

                start+= rowCount;
            }
            return null;
        }
    }
}
